<template>
  <div
    class="chart-box"
    style="width: 100%; height: 100%"
    :style="{ backgroundColor: widgetOptions.setup.backgroundColor }"
  >
    <div v-if="!chartStatus" ref="chartRef" style="width: 100%; height: 100%"></div>

    <ChartEmpty v-if="chartStatus" :chartStatus="chartStatus" />
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import * as echarts from 'echarts'
import { mapper } from '../constants'
import { useTools } from '../../hooks/useTools'
import { useWidgetTools } from '../../hooks/useWidgetTools'
import { useSignalView } from '../../hooks/useSignalView'
import ChartEmpty from '../../components/chartEmpty.vue'

// 接收父组件传入的值
const props = defineProps({
  widgetOptions: {
    type: Object as PropType<Record<string, any>>, // 或更具体的类型
    required: true
  },
  isPreview: {
    type: Boolean,
    default: false
  }
})

const chartRef = ref<HTMLDivElement | null>(null)
let myChart: echarts.ECharts | null = null
const chartData = ref<any>(null)
const { renderErrorBar } = useWidgetTools()

const { toRgba } = useTools()
const mockDataUrl = '/mockdata/realtime/envSpectrumPfStatistics.json'

const initChart = () => {
  if (chartRef.value) {
    // 初始化实例
    myChart = echarts.init(chartRef.value)
  }
}

// 更新配置
const updateOptions = () => {
  if (!chartData.value) return
  const { signalName, startTime, duration, value, extra } = chartData.value
  const signalLabel = mapper[signalName] || ''

  const {
    avg,
    median,
    std,
    se,
    variance,
    iqr,
    idr,
    mad,
    range,
    max,
    min,
    percentile5,
    percentile25,
    percentile75,
    percentile95
  } = value
  const keys = Object.keys(value)
  const series: any[] = []
  //大数据量时，使用折线图
  const isLarge = (value) => {
    return value?.length > 400
  }
  const getBaseSeries = (name, data, highLight) => {
    const large = isLarge(data)
    return {
      name: name,
      type: large ? 'line' : 'bar',
      data: data,
      label: {
        show: !large,
        position: 'top',
        formatter: function (params) {
          const { data } = params
          return data[1].toFixed(2)
        }
      },
      smooth: props.widgetOptions.setup.lineSmooth,
      showSymbol: false,
      itemStyle: {
        color: function (param) {
          return highLight?.includes(param.dataIndex)
            ? props.widgetOptions.setup.barColor
            : props.widgetOptions.setup.barColor2
        }
      },
      lineStyle: {
        width: props.widgetOptions.setup.lineWidth,
        color: props.widgetOptions.setup.lineColor
      },
      areaStyle: props.widgetOptions.setup.areaStyle
        ? {
            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
              {
                offset: 0,
                color: props.widgetOptions.setup.lineColor
              },
              {
                offset: 1,
                color: toRgba(props.widgetOptions.setup.lineColor, 0.3)
              }
            ])
          }
        : null,
      large
    }
  }
  const appendSeries = (name, v1, v2) => {
    const large = isLarge(v1)
    if (large) {
      series.push({
        name: name,
        type: 'line',
        data: v1,
        showSymbol: false
      })
      series.push({
        name: name,
        type: 'line',
        data: v2.map((p) => [p[0], p[1]]),
        lineStyle: {
          opacity: 0
        },
        stack: `stack_${name}`,
        symbol: 'none'
      })
      series.push({
        name: name,
        type: 'line',
        data: v2.map((p) => [p[0], p[2] - p[1]]),
        lineStyle: {
          opacity: 0
        },
        areaStyle: {
          color: '#ccc'
        },
        stack: `stack_${name}`,
        symbol: 'none'
      })
    } else {
      series.push(getBaseSeries(name, v1, extra?.highLight))
      series.push({
        name: name,
        type: 'custom',
        itemStyle: {
          borderWidth: 1.5,
          color: 'red'
        },
        data: v2,
        renderItem: renderErrorBar,
        encode: { tooltip: [1, 2] },
        z: 100
      })
    }
  }

  //均值-标准误
  appendSeries(
    `${mapper['avg'] || 'avg'}_${mapper['se'] || 'se'}`,
    avg,
    avg.map((p, index) => [p[0], p[1] - se[index][1], p[1] + se[index][1]])
  )
  //均值-标准差
  appendSeries(
    `${mapper['avg'] || 'avg'}_${mapper['std'] || 'std'}`,
    avg,
    avg.map((p, index) => [p[0], p[1] - std[index][1], p[1] + std[index][1]])
  )
  //中位数-Q1-Q3
  appendSeries(
    `${mapper['median'] || 'median'}_Q1-Q3`,
    median,
    median.map((p, index) => [p[0], percentile25[index][1], percentile75[index][1]])
  )
  //中位数-5-95
  appendSeries(
    `${mapper['median'] || 'median'}_5th-95th`,
    median,
    median.map((p, index) => [p[0], percentile5[index][1], percentile95[index][1]])
  )
  //中位数-绝对中位差
  appendSeries(
    `${mapper['median'] || 'median'}_${mapper['mad'] || 'mad'}`,
    median,
    median.map((p, index) => [p[0], p[1] - mad[index][1], p[1] + mad[index][1]])
  )

  keys.forEach((key) => {
    series.push(getBaseSeries(mapper[key] || key, value[key], extra?.highLight))
  })
  const option = {
    title: {
      text: `最近${duration}秒${signalLabel}`,
      subtext: `开始时间：${startTime}`,
      left: 'center',
      textStyle: {
        color: props.widgetOptions.setup.titleColor,
        fontSize: props.widgetOptions.setup.titleFontSize
      },
      subtextStyle: {
        color: props.widgetOptions.setup.subtitleColor,
        fontSize: props.widgetOptions.setup.subtitleFontSize
      }
    },
    tooltip: {
      trigger: 'axis'
    },
    dataZoom: [
      {
        type: 'inside',
        xAxisIndex: 0,
        filterMode: 'none'
      },
      {
        type: 'slider',
        xAxisIndex: 0,
        filterMode: 'none'
      }
    ],
    toolbox: {
      itemSize: 25,
      top: 20,
      right: 20,
      feature: {
        magicType: {
          type: ['line', 'bar']
        }
      },
      iconStyle: {
        color: props.widgetOptions.setup.toolboxIconColor,
        borderColor: props.widgetOptions.setup.toolboxIconColor
      }
    },
    legend: {
      type: 'scroll',
      top: '5%',
      left: '10',
      orient: 'vertical',
      selectedMode: 'single',
      itemStyle: {
        color: props.widgetOptions.setup.legendColor
      },
      textStyle: {
        color: props.widgetOptions.setup.legendFontColor,
        fontSize: props.widgetOptions.setup.legendFontSize
      }
    },
    grid: {
      left: '180',
      top: '80',
      right: '3%'
    },
    xAxis: {
      type: 'category',
      axisLine: {
        show: true,
        lineStyle: {
          color: props.widgetOptions.setup.xLineColor
        }
      },
      axisLabel: {
        color: props.widgetOptions.setup.xFontColor,
        fontSize: props.widgetOptions.setup.xFontSize
      }
    },
    yAxis: {
      axisLabel: {
        color: props.widgetOptions.setup.yFontColor,
        fontSize: props.widgetOptions.setup.yFontSize
      },
      splitLine: {
        show: props.widgetOptions.setup.ySplitLine,
        lineStyle: {
          color: 'rgba(255,255,255,0.2)'
        }
      }
    },
    series: series
  }

  myChart?.setOption(option)
  myChart?.resize()
}

const resolveData = (data: any) => {
  if (data && data.msgPack) {
    chartStatus.value = ''
    chartData.value = data.msgPack
    updateOptions()
  } else {
    chartStatus.value = 'noData'
    chartData.value = null
  }
}

const resolveMockData = (data: any) => {
  chartData.value = data
  updateOptions()
}

const { chartStatus, refreshData } = useSignalView(
  props.widgetOptions,
  props.isPreview,
  mockDataUrl,
  resolveData,
  resolveMockData
)

onMounted(() => {
  initChart()
  refreshData()
})

// 如果父组件传入的 props.value 改变，需要更新折线图颜色等
watch(
  () => props.widgetOptions,
  () => {
    if (myChart) {
      updateOptions()
    }
  },
  { immediate: true, deep: true }
)

onBeforeUnmount(() => {
  if (myChart) {
    myChart.dispose()
  }
})
</script>

<style scoped></style>
